using System;
using PluginFrame;

namespace PcrDataAnalysis
{
    /// <summary>
    /// 
    /// </summary>
    public class BaseLineNormalization : IBaseLineNormalization
    {
        protected int mStartBaseLine;

        protected int mStopBaseLine;

        protected IConfigurationService mConfigurationService;

        protected int[] mDigitalFilerFactor;

        protected IAbsoluteAnalysisParameterConfiguration mAnalysisOption;

        public BaseLineNormalization(IApplication app)
        {
            mConfigurationService = (IConfigurationService)app.GetService("ConfigurationService");
            mDigitalFilerFactor = new int[9];
            mDigitalFilerFactor[0] = -252;
            mDigitalFilerFactor[1] = 168;
            mDigitalFilerFactor[2] = 468;
            mDigitalFilerFactor[3] = 648;
            mDigitalFilerFactor[4] = 708;
            mDigitalFilerFactor[5] = 648;
            mDigitalFilerFactor[6] = 468;
            mDigitalFilerFactor[7] = 168;
            mDigitalFilerFactor[8] = -252;
        }

        protected virtual double DigitalFilter(double[] filterValue)
        {
            double num = 0.0;
            double num2 = 0.0;
            for (int i = 0; i < filterValue.Length; i++)
            {
                num += filterValue[i] * (double)mDigitalFilerFactor[i];
                num2 += (double)mDigitalFilerFactor[i];
            }
            return num / num2;
        }

        protected virtual void ProcessDigitalFilter(IPcrCell pcrCell, int intChannelIndex, int dataLength)
        {
            double[] array = new double[dataLength + 8];
            for (int i = 0; i < dataLength; i++)
            {
                array[i + 4] = pcrCell.GetNormalLightData(intChannelIndex, i + 1);
            }
            for (int j = 0; j < 4; j++)
            {
                array[j] = pcrCell.GetNormalLightData(intChannelIndex, 1);
            }
            for (int k = array.Length - 4; k < array.Length; k++)
            {
                array[k] = pcrCell.GetNormalLightData(intChannelIndex, dataLength);
            }
            for (int l = 0; l < dataLength; l++)
            {
                int num = 0;
                double[] array2 = new double[9];
                for (int m = l; m < l + 9; m++)
                {
                    array2[num++] = array[m];
                }
                pcrCell.SetNormalLightData(intChannelIndex, l + 1, DigitalFilter(array2));
            }
        }

        protected virtual double CalculateBaseLineAverage(double[] channelData, int startBaseLine, int stopBaseLine)
        {
            double num = 0.0;
            double num2 = 0.0;
            for (int i = startBaseLine; i <= stopBaseLine; i++)
            {
                if (i - 1 < channelData.Length)
                {
                    num += ((!double.IsNaN(channelData[i - 1])) ? channelData[i - 1] : 0.0);
                    num2 += 1.0;
                }
            }
            return num / num2;
        }

        protected virtual void ChannelNormalization(IPcrCell pcrCell, int channelIndex, bool isAnalyzing, int startBaseLine, int stopBaseLine, double[] channelData)
        {
            if (isAnalyzing)
            {
                double num = CalculateBaseLineAverage(channelData, startBaseLine, stopBaseLine);
                pcrCell.SetBaseLineAvgValue(channelIndex, num);
                for (int i = 0; i < channelData.Length; i++)
                {
                    channelData[i] = Math.Log(channelData[i] / num, 2.0);
                    pcrCell.SetNormalLightData(channelIndex, i + 1, channelData[i]);
                }
            }
        }

        public AnalysisError Execute(IPcrCell pcrCell, IAbsoluteAnalysisParameterConfiguration analysisOption, int channelIndex, bool isAnalyzing)
        {
            mAnalysisOption = analysisOption;
            double[] array = ProccessBaseLineValue(analysisOption, isAnalyzing, pcrCell, channelIndex);
            if (array != null)
            {
                ChannelNormalization(pcrCell, channelIndex, isAnalyzing, mStartBaseLine, mStopBaseLine, array);
                if (analysisOption.IsDigitalFilter && isAnalyzing)
                {
                    ProcessDigitalFilter(pcrCell, channelIndex, array.Length);
                }
                return AnalysisError.NA;
            }
            return AnalysisError.LessCycle;
        }

        protected virtual double[] ProccessBaseLineValue(IAbsoluteAnalysisParameterConfiguration analysisOption, bool isAnalyzing, IPcrCell pcrCell, int channelIndex)
        {
            mStartBaseLine = analysisOption.StartBaseline;
            mStopBaseLine = analysisOption.StopBaseline;
            double[] channelRawData = pcrCell.GetChannelRawData(channelIndex, true);
            if (channelRawData.Length < 3)
            {
                return null;
            }
            if (mStartBaseLine >= channelRawData.Length)
            {
                mStartBaseLine = channelRawData.Length - 2;
                mStopBaseLine = channelRawData.Length - 1;
            }
            else if (mStopBaseLine >= channelRawData.Length)
            {
                mStopBaseLine = channelRawData.Length - 1;
            }
            int num = mStartBaseLine;
            int num2 = mStopBaseLine;
            for (int i = mStartBaseLine - 1; i < mStopBaseLine && (i >= channelRawData.Length || double.IsNaN(channelRawData[i])); i++)
            {
                if (num == 1)
                {
                    break;
                }
                num++;
            }
            mStartBaseLine = num;
            int num3 = mStopBaseLine - 1;
            while (num3 > mStartBaseLine && (num3 >= channelRawData.Length || double.IsNaN(channelRawData[num3])))
            {
                num2--;
                num3--;
            }
            mStopBaseLine = num2;
            if (mStopBaseLine >= channelRawData.Length)
            {
                mStopBaseLine = channelRawData.Length - 1;
            }
            if (mStartBaseLine >= mStopBaseLine)
            {
                mStartBaseLine = mStopBaseLine - 1;
            }
            if (mStartBaseLine <= 0)
            {
                return null;
            }
            return channelRawData;
        }
    }
}
